﻿/**
 * TraceListener.cs
 *  Listening server to process GPS trace signals
 *  (first point of entry for GPS broadcasts)
 */

using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Data.SqlClient;
using Newtonsoft.Json;
using System.Web.Script.Serialization;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Threading;
using System.Web;


/**
 * TraceListener server listens for and processes incoming GPS trace broadcasts
 */
public class TraceListener : IObservable<Trace>, IDisposable
{
    private List<IObserver<Trace>> _observers;
    private static bool _done;
    private HttpListener _httpListener;
    
    public TraceListener()
    {
        //Console.WriteLine("TRACELISTENER -- In TraceListener's constructor, creating a Worker and starting it on its own Thread");
        _done = false;
        _observers = new List<IObserver<Trace>>();
        //new Thread(new Worker(this).Listen).Start();


        _httpListener = new HttpListener();
        _httpListener.Prefixes.Add("http://192.168.1.199:13000/");
        _httpListener.Start();
        //Console.WriteLine("Listening...");
        //for (; ; )
        //{
        //    HttpListenerContext context = httpListener.GetContext();
        //    new Thread(new Worker(context, this).ProcessRequest).Start();
        //}
    }

    public void listen()
    {
        Console.WriteLine("Listening...");
        for (; ; )
        {
            HttpListenerContext context = _httpListener.GetContext();
            new Thread(new Worker(context, this).ProcessRequest).Start();
        }
    }

    public static void Main_____()
    {
        //Console.WriteLine("MAIN -- Starting Main() in TraceListener");

        //Console.WriteLine("MAIN -- Starting TraceListener observable source");
        //TraceListener listener = new TraceListener();

        //TraceHandler handler = new TraceHandler(listener, "192.168.1.199", "CriminalTracker");

        //Console.WriteLine("MAIN -- Subscribing TraceHandler to TraceListener");
        //handler.Subscribe(listener);

        //Console.WriteLine("MAIN -- Entering while true loop");
        //while (true)
        //{

        //}

        
    }

    public IDisposable Subscribe(IObserver<Trace> observer)
    {
        //Console.WriteLine("TRACELISTENER -- TraceListener.Subscribe(handler) called");
        _observers.Add(observer);
        return new Subscription(this, observer);
    }

    public void OnNext(Trace trace)
    {
        //Console.WriteLine("TRACELISTENER ONNEXT");
        if (!_done)
        {
            //Console.WriteLine("TRACELISTENER -- In TraceListener's OnNext");
            if (_observers != null)
            {
                foreach (var observer in _observers)
                {
                    
                    observer.OnNext(trace);
                }
            }
        }
    }

    public void OnError(Exception e)
    {
        //foreach (var observer in _observers)
        //{
        //    observer.OnError(e);
        //}
        //_done = true;
    }

    public void OnCompleted()
    {
        //Console.WriteLine("entering listener's oncompleted");
        foreach (var observer in _observers)
        {
            observer.OnCompleted();
        }
        _done = true;
    }

    void IDisposable.Dispose()
    {
        // this is where tracelistener should release all its resources
    }

    private sealed class Subscription : IDisposable
    {
        private readonly TraceListener _listener;
        private IObserver<Trace> _observer;

        public Subscription(TraceListener listener, IObserver<Trace> observer)
        {
            _listener = listener;
            _observer = observer;
        }

        public void Dispose()
        {
            //IObserver<Trace> observer = _observer;
            //if (null != observer)
            //{
            //    _listener._observers.Remove(observer);
            //    _observer = null;
            //}
        }
    }
}

class Worker
{
    //Listener configuration
    //private TcpListener _server = null;
    //private IPAddress _listenerServer;
    //private Int32 _listenerPort;

    private TraceListener _listener;
    //private List<TraceSource> _sources;

    // Constants
    //private const string LISTENERSERVER = "192.168.1.199";
    //private const int LISTENERPORT = 13000;

    private HttpListenerContext _context;

    public Worker(HttpListenerContext context, TraceListener listener)
    {
        //_sources = new List<TraceSource>();
        //_listener = _listener;
        //_listenerServer = IPAddress.Parse(LISTENERSERVER);
        //_listenerPort = LISTENERPORT;

        _context = context;
        _listener = listener;
    }

    public void ProcessRequest()
    {
        string msg = _context.Request.HttpMethod + " " + _context.Request.Url;
        //Console.WriteLine("CHECK: " + msg);

        

        String trace;
        

        //trace = context.Request.QueryString.GetValues(0);
        //Console.WriteLine("received trace of size: " + trace[0].Length);
        //Console.WriteLine("TRACE:   " + trace[0].ToString());

        using (Stream stream = _context.Request.InputStream)
        {
            using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
            {
                trace = reader.ReadToEnd();

                //trace = context.Request.QueryString.GetValues(0);
                //Console.WriteLine("TRACE:   " + trace[0].ToString());

                
            }
        }

        //Console.WriteLine("HTTP POST BODY:   " + trace.ToString());

        //byte[] myReadBuffer = new byte[1024];
        StringBuilder myCompleteMessage = new StringBuilder(trace.ToString());
        //int numberOfBytesRead = 0;

        //// if incoming data is larger than buffer, loop to next chunk and append to string
        //do
        //{
        //    numberOfBytesRead = ClientStream.Read(myReadBuffer, 0, myReadBuffer.Length);
        //    myCompleteMessage.AppendFormat("{0}", Encoding.UTF8.GetString(myReadBuffer, 0, numberOfBytesRead));
        //}
        //while (ClientStream.DataAvailable);

        // deserialize json string into Trace object
        JavaScriptSerializer JSS = new JavaScriptSerializer();
        
        Trace traceObj = JSS.Deserialize<Trace>(myCompleteMessage.ToString());
        //Console.WriteLine("Incoming trace:" + myCompleteMessage.ToString());
        _listener.OnNext(traceObj);
        //Console.WriteLine("called onnext");

        
    }

    //public void Listen()
    //{
    //    try
    //    {
    //        _server = new TcpListener(_listenerServer, _listenerPort);
            
    //        // Buffer for reading data
    //        Byte[] bytes = new Byte[256];
    //        // Start listening for gps traces
    //        _server.Start();

    //        // Enter the listening loop. 
    //        while (true)
    //        {
    //            //Console.WriteLine("WORKER -- waiting for a connection...");

    //            // Perform a blocking call to accept requests. 
    //            TcpClient client = this._server.AcceptTcpClient();
    //            //Console.WriteLine("WORKER -- connected!");

    //            TraceSource source = new TraceSource(client, _listener);

    //            //Console.WriteLine("WORKER -- passing incoming connection to TraceSource.processTrace() in a new Thread");
    //            new Thread(source.processTrace).Start();

    //            _sources.Add(source);
    //        }
    //    }
    //    catch (SocketException e)
    //    {
    //        Console.WriteLine("SocketException: {0}", e);
    //    }
    //    catch (Exception e)
    //    {
    //        Console.WriteLine(e.ToString());
    //    }
    //    finally
    //    {
    //        // Stop listening for new clients.
    //        this._server.Stop();
    //    }
    //    Console.WriteLine("\nHit enter to continue...");
    //    Console.Read();

    //}
}

//class TraceSource
//{
//    TraceListener _listener;
//    TcpClient _client;

//    public TraceSource(TcpClient client, TraceListener listener)
//    {
//        _listener = listener;
//        _client = client;
//    }

//    public void processTrace()
//    {

//        // Get a stream object for reading and writing
//        NetworkStream ClientStream = _client.GetStream();

//        // if the stream has data to read
//        if (ClientStream.CanRead)
//        {
//            byte[] myReadBuffer = new byte[1024];
//            StringBuilder myCompleteMessage = new StringBuilder();
//            int numberOfBytesRead = 0;

//            // if incoming data is larger than buffer, loop to next chunk and append to string
//            do
//            {
//                numberOfBytesRead = ClientStream.Read(myReadBuffer, 0, myReadBuffer.Length);
//                myCompleteMessage.AppendFormat("{0}", Encoding.UTF8.GetString(myReadBuffer, 0, numberOfBytesRead));
//            }
//            while (ClientStream.DataAvailable);

//            // deserialize json string into Trace object
//            JavaScriptSerializer JSS = new JavaScriptSerializer();
//            Trace trace = JSS.Deserialize<Trace>(myCompleteMessage.ToString());

//            //Console.WriteLine("TRACESOURCE -- received trace:" + trace.ToString());
            
//            //Console.WriteLine("TRACESOURCE -- calling TraceListener's OnNext()");
//            _listener.OnNext(trace);
//        }
//        else
//        {
//            Console.WriteLine("TRACESOURCE -- Cannot read from NetworkStream");
//        }
//        // Shutdown and end connection
//        _client.Close();
//    }

//}

